package com.jdy.haoduoaiteacher.socket;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.jdy.haoduoaiteacher.MyTeacherApp;
import com.jdy.haoduoaiteacher.enums.MediaType;
import com.jdy.haoduoaiteacher.enums.PlayState;
import com.jdy.haoduoaiteacher.model.DownloadProgress;
import com.jdy.haoduoaiteacher.model.DownloadStateModel;
import com.jdy.haoduoaiteacher.model.LeMachine;
import com.jdy.haoduoaiteacher.model.LeUser;
import com.jdy.haoduoaiteacher.model.SocketMachineInfo;
import com.jdy.haoduoaiteacher.parse.JsonSerializer;
import com.jdy.haoduoaiteacher.util.LeConfig;
import com.jdy.haoduoaiteacher.util.OnDataReceivedListener;
import com.jdy.haoduoaiteacher.util.Tools;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;

public class SocketInputThread extends Thread {
  private boolean isStart = true;
  static final String TAG = SocketInputThread.class.getSimpleName();
  private static String tag = "socket";
  String tel;
  private Context context;
  Intent status;
//  char a = (char) 1;
  char b = (char) 0;

//  public static int PREFIX = 1;
  //public static int SUFFIX = 2;

  // PyCmd cmd_book;
  // List<RemoteDownloadItem> downloadlist = null;
  int size, page, allpage;

  public SocketInputThread() {
    context = MyTeacherApp.getAppContext();
    status = new Intent("hk.com.dycx.intent.action.DEVICE_CONNECT_STATUS");
  }

  public void setStart(boolean isStart) {
    this.isStart = isStart;
  }

  @Override
  public void run() {
    while (isStart) {
      if (Tools.isNetworkAvailable(context)) {

        if (!TCPClient.instance().isConnect()) {
          // CLog.e(tag,
          // "TCPClient connet server is fail read thread sleep second"
          // + Const.SOCKET_SLEEP_SECOND);
          TCPClient.instance().reConnect();
          try {
            sleep(Const.SOCKET_SLEEP_SECOND * 1000);
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }

        readSocket();

        // CLog.e("socket","TCPClient.instance().isConnect() " +
        // TCPClient.instance().isConnect() );

      }
    }
  }

  public void readSocket() {
    Selector selector = TCPClient.instance().getSelector();
    if (selector == null) {
      return;
    }
    try {
      while (selector.select() > 0) {
        for (SelectionKey sk : selector.selectedKeys()) {
          if (sk.isReadable()) {
            SocketChannel sc = (SocketChannel) sk.channel();
            ByteBuffer buffer = ByteBuffer.allocate(10240);
            try {
              sc.read(buffer);
            } catch (IOException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
              // continue;
            }
            buffer.flip();
            String receivedString = "";
            try {
              receivedString = Charset.forName("UTF-8").newDecoder()
                  .decode(buffer).toString();
              if (!receivedString.equals("")) {
                // String received = receivedString.replace(String.valueOf(a),
                // "").replace(String.valueOf(b), "");
                System.out.println("=======xxb===receivedString======"
                    + receivedString);
                if (receivedString.contains("heartbeat")
                    || receivedString.contains("connect")) {
                  LeConfig.lasttime = System.currentTimeMillis();
                }
                if (Const.connectF != 2) {
                  System.out.println("====xxb===Const.connectF===="
                      + Const.connectF);
                  status.putExtra("flag_online", 2);
                  context.sendBroadcast(status);
                  Const.connectF = 2;
                }
                String[] received = receivedString.split(String.valueOf(b));
                for (int i = 0; i < received.length; i++) {
                  handleAct(received[i].replace(
                      String.valueOf(b), ""));
                }
                // handleAct(received);
              }
            } catch (CharacterCodingException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }
            buffer.clear();
            buffer = null;

            try {
              sk.interestOps(SelectionKey.OP_READ);
              selector.selectedKeys().remove(sk);

            } catch (CancelledKeyException e) {
              e.printStackTrace();
            }

          }
        }
      }
      // selector.close();
      // TCPClient.instance().repareRead();

    } catch (IOException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    } catch (ClosedSelectorException e2) {
      e2.printStackTrace();
    } catch (CancelledKeyException e3) {
      e3.printStackTrace();
    }
  }

  /**
   * 
   * Update: 0 ---> not necessary 1 ---> necessary 2 ---> updating
   * 
   * @param jsonObject
   */
  private void parseMachineInfo(JSONObject jsonObject) {
    if (jsonObject.has("update")) {

      final SocketMachineInfo sMInfo = JsonSerializer.getInstance()
          .deserialize(jsonObject.toString(), SocketMachineInfo.class);

      if (sMInfo != null) {
        if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
          if (!SocketThreadManager.getInstance().mDeviceHasUpgraded) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                .getDeviceStateListeners()) {
              dsl.onUpgrade(sMInfo.update);
            }
            SocketThreadManager.getInstance().mDeviceHasUpgraded = true;
          }

          if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                .getDeviceStateListeners()) {
              dsl.onPowerChanged(sMInfo.power);
            }
          }
        }

        Intent macInfoChangedIntent = new Intent("device.details.update.event");
        macInfoChangedIntent.putExtra("socketmachineinfo", sMInfo);
        context.sendBroadcast(macInfoChangedIntent);
      }
    } else {
      final SocketMachineInfo sMInfo = JsonSerializer.getInstance()
              .deserialize(jsonObject.toString(), SocketMachineInfo.class);

      if (sMInfo != null) {
        if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
          if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                    .getDeviceStateListeners()) {
              dsl.onPowerChanged(sMInfo.power);
            }
          }
        }

        Intent macInfoChangedIntent = new Intent("device.details.update.event");
        macInfoChangedIntent.putExtra("socketmachineinfo", sMInfo);
        context.sendBroadcast(macInfoChangedIntent);
      }
    }
  }

//  /**
//   * Ensure the integer is valid.
//   *
//   * @param version
//   */
  @SuppressWarnings("unused")
//  private void checkIfDeviceMatch(String version) {
//    try {
//      int currentDeviceVersion = Integer
//          .valueOf(version.replaceAll("\\D+", ""));
//      if (currentDeviceVersion < 201) {
//        LeConfig.isDeviceVersionMatch = false;
//      } else {
//        LeConfig.isDeviceVersionMatch = true;
//        // LePreferences le = StoreBox.create(this, LePreferences.class);
//        // le.setDeviceVersion(version);
//      }
//    } catch (NumberFormatException nfe) {
//      return;
//    }
//  }

//  private String fabricateCommand(JSONObject content, int codeValue) {
//    JSONObject rawCommand = new JSONObject();
//    try {
//      rawCommand.put("data", content);
//      rawCommand.put("code", codeValue);
//    } catch (JSONException e) {
//
//      e.printStackTrace();
//    }
//    String commandString =  rawCommand.toString()
//        + (char) 0;
//    return commandString;
//  }

//  public void requestUpgrade() {
//
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "update");
//      String updateCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", updateCmd);
//
//      TCPClient.instance().sendMsg(updateCmd.toString());
//      // sendSocket(updateCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

//  public void playNext() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "next");
//      String nextCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", nextCmd);
//      TCPClient.instance().sendMsg(nextCmd.toString());
//      // sendSocket(nextCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

//  public void playForward() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "speed");
//      String nextCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", nextCmd);
//
//      TCPClient.instance().sendMsg(nextCmd.toString());
//      // sendSocket(nextCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }
//
//  public void playRewind() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "rewind");
//      String nextCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", nextCmd);
//      TCPClient.instance().sendMsg(nextCmd.toString());
//      // sendSocket(nextCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

//  public void playPrev() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "prev");
//      String prevCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", prevCmd);
//      TCPClient.instance().sendMsg(prevCmd.toString());
//      // sendSocket(prevCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

//  public void playPause() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "pause");
//      String pauseCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", pauseCmd);
//
//      TCPClient.instance().sendMsg(pauseCmd.toString());
//
//      // sendSocket(pauseCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

//  public void playResume() {
//    try {
//      JSONObject jsonObject = new JSONObject();
//      jsonObject.put("type", "cartoon");
//      jsonObject.put("op", "resume");
//      String resumeCmd = fabricateCommand(jsonObject, 202);
//      Log.e("socket", resumeCmd);
//      TCPClient.instance().sendMsg(resumeCmd.toString());
//      // sendSocket(resumeCmd.toString());
//    } catch (JSONException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    } catch (IOException e) {
//      // TODO Auto-generated catch block
//      e.printStackTrace();
//    }
//  }

  public void requestDeviceDetails() {
    try {
      JSONObject dataJson = new JSONObject();
      dataJson.put("code", 202);
      dataJson.put("act", "machineinfo");
      TCPClient.instance().sendMsg(dataJson.toString() + (char) 0);

      // sendSocket(getDetailsCmd.toString());
    } catch (JSONException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void parseVoiceMessageResponse(JSONObject jsonObject) {
    if (jsonObject.has("stream")) {
      try {
        String voiceUrl = jsonObject.getString("stream");
        if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
          for (DeviceStateListener dsl : SocketThreadManager.getInstance()
              .getDeviceStateListeners()) {
            dsl.onReceivedVoiceMessage(voiceUrl);
          }
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
  }

  private void parseDeviceActionResponse(JSONObject jsonObject) {
    if (jsonObject.has("type")) {
      try {
        String actionType = jsonObject.getString("type");
        if ("cartoon".equals(actionType) || "story".equals(actionType)
            || "radio".equals(actionType) || "dub".equals(actionType)
            || "mine_story".equals(actionType) || "book".equals(actionType)
            || "education".equals(actionType)) {
          Log.e(TAG, "video data info from device===>" + jsonObject.toString());
          parseCartoonInfo(jsonObject);
        } else if ("machineinfo".equals(actionType)) {
          Log.e(TAG,
              "machineinfo data info from device===>" + jsonObject.toString());
          parseMachineInfo(jsonObject);
        } else if ("radio".equals(actionType)) {
          Log.e(TAG, "radio data info from device===>" + jsonObject.toString());
          parseRadioInfo(jsonObject);
        } else if ("pre".equals(actionType)) {
          if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                .getDeviceStateListeners()) {
              dsl.onPlayPrevFailed();
            }
          }
        } else if ("next".equals(actionType)) {
          if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                .getDeviceStateListeners()) {
              dsl.onPlayNextFailed();
            }
          }
        } else if ("downloadstate".equals(actionType)) { // 下载进度
          parseDownloadStateInfo(jsonObject);
        } else if ("getdownloadlist".equals(actionType)) {
          parseDownloadListInfo(jsonObject);
        } else if ("downloadsize".equals(actionType)) {
          if (jsonObject.has("size")) {
            if (SocketThreadManager.getInstance().getDownloadStateListener() != null) {
              for (DownloadStateListener dsl : SocketThreadManager
                  .getInstance().getDownloadStateListener()) {
                dsl.downLoadSize(jsonObject.getInt("size"));
              }
            }
          }
        } else {
          Log.e(TAG, "other data info from device===>" + jsonObject.toString());
          parseOtherInfo(jsonObject);
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    } else {// when there is no type in the content!
      if (jsonObject.has("power") && jsonObject.has("discsize") && jsonObject.has("usesize")) {
        parseMachineInfo(jsonObject);
      } else {
        parseNoTypeInfo(jsonObject);
      }
    }
  }

  private void parseDownloadListInfo(JSONObject jsonObject) {
    final DownloadStateModel data = JsonSerializer.getInstance().deserialize(
        jsonObject.toString(), DownloadStateModel.class);

    if (SocketThreadManager.getInstance().getDownloadStateListener() != null) {
      for (DownloadStateListener dsl : SocketThreadManager.getInstance()
          .getDownloadStateListener()) {
        dsl.onDownloadList(data);
      }
    }
  }

  private void parseRadioInfo(JSONObject jsonObject) {
    try {
      String playState = "";
      if (jsonObject.has("PlayState")) {
        playState = jsonObject.getString("PlayState");
      }

      PlayState state = PlayState.None;
      state =  getPlayStateByString(playState);

      if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
        for (DeviceStateListener dsl : SocketThreadManager.getInstance()
            .getDeviceStateListeners()) {
          dsl.onPlayMedia(state, MediaType.Radio, jsonObject);
        }
      }
    } catch (JSONException e) {
      e.printStackTrace();
    }
  }

  private void parseCartoonInfo(JSONObject jsonObject) {
    try {
      if (jsonObject.has("VideoId")) {
        int id = jsonObject.getInt("VideoId");
        if (id == -1)
          return;
      }

      PlayState state = PlayState.None;

      if (jsonObject.has("PlayState")) {
        String playState = jsonObject.getString("PlayState");
        state =  getPlayStateByString(playState);
      }

      if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
        for (DeviceStateListener dsl : SocketThreadManager.getInstance()
            .getDeviceStateListeners()) {
          dsl.onPlayMedia(state, MediaType.Collection, jsonObject);
        }
      }
    } catch (JSONException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void parseNoTypeInfo(JSONObject jsonObject) {
    try {
      String playState = "";

      if (jsonObject.has("PlayState")) {
        playState = jsonObject.getString("PlayState");
      }
      PlayState state = PlayState.None;
      state = getPlayStateByString(playState);

      if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
        for (DeviceStateListener dsl : SocketThreadManager.getInstance()
            .getDeviceStateListeners()) {
          dsl.onPlayMedia(state, MediaType.NoType, jsonObject);
        }
      }
    } catch (JSONException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  private void parseHeartbeat(JSONObject jsonObject) {
    // TODO Auto-generated method stub
    if (jsonObject.has("type")) {
      try {
        String connectResult = jsonObject.getString("type");
        Log.e(TAG, "Heartbeat ====>" + connectResult);
      } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  private void parseConnection(JSONObject jsonObject) {
    // TODO Auto-generated method stub
    if (jsonObject.has("type")) {
      try {
        String connectResult = jsonObject.getString("type");
        Log.e(TAG, "Type of connection" + connectResult);
      } catch (JSONException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  private PlayState getPlayStateByString(String state) {
    if (Tools.isNotEmpty(state)) {
      if ("playing".equals(state)) {
        return PlayState.Playing;
      } else if ("pause".equals(state)) {
        return PlayState.Pause;
      } else if ("stop".equals(state)) {
        return PlayState.Stop;
      }
    } else {
      return PlayState.None;
    }

    return PlayState.None;
  }

  private void parseOtherInfo(JSONObject jsonObject) {
    String playState = "";
    try {
      if (jsonObject.has("PlayState")) {
        playState = jsonObject.getString("PlayState");
      }
      PlayState state = PlayState.None;
      state = getPlayStateByString(playState);
      if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
        for (DeviceStateListener dsl : SocketThreadManager.getInstance()
            .getDeviceStateListeners()) {
          dsl.onPlayMedia(state, MediaType.OtherType, jsonObject);
        }
      }
    } catch (JSONException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  /**
   * 解析下载进度
   * 
   * @param jsonObject
   */
  @SuppressWarnings("unused")
  private void parseDownloadStateInfo(JSONObject jsonObject) {
    final DownloadProgress data = JsonSerializer.getInstance().deserialize(
        jsonObject.toString(), DownloadProgress.class);

    if (SocketThreadManager.getInstance().getDownloadStateListener() != null) {
      for (DownloadStateListener dsl : SocketThreadManager.getInstance()
          .getDownloadStateListener()) {
        dsl.onDownloadState(data);
      }
    }
  }

  @SuppressWarnings("static-access")
  private void handleAct(String data) {

    Log.e("fffffffffsdfdsffff", data);

    try {
      JSONObject jsonData = new JSONObject(data.toString());
      int retCode = -1;
      if (!jsonData.isNull("code")) {
        retCode = jsonData.getInt("code");
        switch (retCode) {
//          case -1:
//            TCPClient.instance().reConnect();
//            break;
        case -3:
          SocketThreadManager.getInstance().stopThreads();
          SocketThreadManager.getInstance().releaseInstance();
          // exitSocketConn();
          if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
            for (DeviceStateListener dsl : SocketThreadManager.getInstance()
                .getDeviceStateListeners()) {
              dsl.onRemoteLogin();
            }
          }
          break;
        case 140:
          if (!jsonData.isNull("data") && data.toString().length() < 25) {
            // 0在线 1离线
            LeConfig.isDeviceOnline = jsonData.getInt("data");

            if (LeConfig.isDeviceOnline == 0) {
              LeMachine lb = MyTeacherApp.getInstance().getBabyTeacher();
              LeUser lu = MyTeacherApp.getInstance().getUserTeacher();
              if (lu != null && lb != null) {
//                ImHelper mImHelper = LeXiaoXiaoBanApp.getInstance()
//                    .getImHelper();
               // if (mImHelper.isLogin()) {
//                  mImHelper.connect(lb.id);

//                  JSONObject jsonObject = new JSONObject();
//                  try {
//                    jsonObject.put("code", 202);
//                    jsonObject.put("act", "connect");
//                    jsonObject.put("data", lu.id);
//
//                    SocketThreadManager.getInstance().send(jsonObject.toString());
//                  } catch (JSONException e) {
//                    e.printStackTrace();
//                  }
             //   }
              }
            }
          }
          break;
        case 100:
          if (jsonData.has("type")) {
            if ("connect".equals(jsonData.getString("type"))) {
              LeConfig.isDeviceConnect = true;
              if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
                for (DeviceStateListener dsl : SocketThreadManager
                    .getInstance().getDeviceStateListeners()) {
                  dsl.onConnectionChanged(true);
                }
              }
              requestDeviceDetails();
            } else {
              LeConfig.isDeviceConnect = false;
              if (SocketThreadManager.getInstance().getDeviceStateListeners() != null) {
                for (DeviceStateListener dsl : SocketThreadManager
                    .getInstance().getDeviceStateListeners()) {
                  dsl.onConnectionChanged(false);
                }
              }
            }
          }
          break;
        case 102:
          if (jsonData.has("data")) {
            parseDeviceActionResponse(jsonData.getJSONObject("data"));

//                  if (SocketThreadManager.getInstance().getOnDataReceivedListener()!= null) {
//        for (OnDataReceivedListener dsl : SocketThreadManager.getInstance()
//                .getOnDataReceivedListener()) {
//          dsl.onDataReceived(data.toString());
//        }
//      }
          }
          break;
        case 110:
          break;
        case 120: // SOCKET语音包
          if (jsonData.has("data")) {
            parseVoiceMessageResponse(jsonData.getJSONObject("data"));
          }
          break;
        case 130:
          break;
        case 150: // rtmp连接状态
          // parseRtmpConnection(jsonData.getJSONObject("data"));
          // TODO
          break;
        case 200:// SOCKET连接包
          if (jsonData.has("data"))
            parseConnection(jsonData.getJSONObject("data"));
          break;
        case 202:// SOCKET操作包
          // if (jsonData.has("data"))
          // parserActionResponse(jsonData.getJSONObject("data"));
          break;
        case 210:// SOCKET心跳包
          if (jsonData.has("data"))
            parseHeartbeat(jsonData);
          break;
        default:
          break;
        }
      }

      if (SocketThreadManager.getInstance().getOnDataReceivedListener()!= null) {
        for (OnDataReceivedListener dsl : SocketThreadManager.getInstance()
                .getOnDataReceivedListener()) {
          dsl.onDataReceived(data.toString());
        }
      }
    } catch (JSONException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }
}
